package com.cg.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cg.common.Constants;
import com.cg.dao.DmImageMapper;
import com.cg.dao.DmUserMapper;
import com.cg.dto.*;
import com.cg.entity.DmImage;
import com.cg.entity.DmUser;
import com.cg.service.DmUserService;
import com.cg.utils.*;
import com.cg.vo.LoginUserVo;
import com.cg.vo.TokenVO;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * 用户表(DmUser)表服务实现类
 *
 * @author makejava
 * @since 2023-11-06 12:02:36
 */
@Service("dmUserService")
@Slf4j
public class DmUserServiceImpl implements DmUserService {
    @Resource
    private DmUserMapper dmUserMapper;

    @Resource
    private DmImageMapper dmImageMapper;

    @Resource
    private RedisUtil redisUtil;


    @Value("${userTokenTimeOut}")
    private Long userTokenTimeOut;

    @Value(("${smsTimeOut}"))
    private Long smsTimeOut;

    @Value(("${resultTimeOut}"))
    private Long resultTimeOut;

    @Resource
    private MQUtil mqUtil;

    //用户登录
    @Override
    public Dto<Object[]> login(LoginDto loginDto) {

        if (loginDto.getPhone() == null || loginDto.getPhone() == "") {
            return DtoUtil.returnEnum(DtoEnum.COMMON_USER_ERROR);
        }

        //通过phone，password查询用户对象
        QueryWrapper<DmUser> queryWrapper = new QueryWrapper<>();//用于组装查询条件
        queryWrapper.eq("phone", loginDto.getPhone());//相当于 =
        DmUser loginUser = dmUserMapper.selectOne(queryWrapper);

        //验证密码

        if (loginUser == null) {
            return DtoUtil.returnEnum(DtoEnum.COMMON_USER_ERROR);
        }
        String passwordMySql = loginUser.getPassword();//数据库中的密码
        String password = loginDto.getPassword();//请求中获取的密码
        //加密密码
        password = MD5Utils.MD5(password);
        if (!password.equals(passwordMySql)) {
            return DtoUtil.returnEnum(DtoEnum.FAIL_LOGIN_PASSWORD_ERROR);
        }

        //组装查询头像
        QueryWrapper<DmImage> queryWrapper1 = new QueryWrapper<>();
        queryWrapper1.eq("targetId", loginUser.getId());
        queryWrapper1.eq("category", 0);
        DmImage dmImage = dmImageMapper.selectOne(queryWrapper1);



        //头像
        LoginUserVo loginUserVo = new LoginUserVo();
        BeanUtils.copyProperties(loginUser, loginUserVo);
        if(dmImage == null){
            loginUserVo.setImgUrl(null);
        }else{
            loginUserVo.setImgUrl(dmImage.getImgUrl());
            loginUserVo.setImageId(dmImage.getId());
        }

        loginUserVo.setUserId(loginUser.getId());

        //将用户对象转换成JSON格式保存到redis中
        String userJson = JSON.toJSONString(loginUser);

        //生成token
        String token = UUIDUtils.getUUID32();
        String key = RedisKeyUtils.formatKeyWithPrefix(Constants.Redis.PREFIX_TOKEN, token);
        TokenVO tokenVO = new TokenVO();
        tokenVO.setToken(token);
        tokenVO.setExpTime(Constants.Redis_Expire.SESSION_TIMEOUT);
        tokenVO.setGenTime(System.currentTimeMillis());
        Object[] objects = new Object[2];
        objects[0] = loginUserVo;
        objects[1] = tokenVO;

        String json = "";
        JsonMapper jsonMapper = JsonMapper.builder().build();

        try {
            json = jsonMapper.writeValueAsString(objects);
            //保存信息到redis中
            redisUtil.setValue(key, json, Constants.Redis_Expire.SESSION_TIMEOUT);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        return DtoUtil.returnDataSuccess(objects);
    }

    //根据token获取用户信息
    @Override
    public Dto<DmUser> findUserByToken(String token) {
        String key = RedisKeyUtils.formatKeyWithPrefix(Constants.Redis.PREFIX_TOKEN, token);
        if (token == null || "".equals(token)) {
            return DtoUtil.returnEnum(DtoEnum.COMMON_LOGIN_USER_ERROR);
        }
        String userJson = redisUtil.get(key);
        if (userJson == null) {
            return DtoUtil.returnEnum(DtoEnum.COMMON_EXCEPTION);
        }

        Object[] objects = JSON.parseObject(userJson, Object[].class);

       /* DmUser dmUser = new DmUser();
        objects[0] = dmUser;*/
        return DtoUtil.returnDataSuccess(objects[0]);
    }

    //刷新Token
    @Override
    public Dto<TokenVO> replaceToken(String token) {
        String key = RedisKeyUtils.formatKeyWithPrefix(Constants.Redis.PREFIX_TOKEN, token);
        if (token == null || token.equals("")) {
            return DtoUtil.returnEnum(DtoEnum.COMMON_LOGIN_USER_ERROR);
        }
        //根据token获取用户信息
        String json = redisUtil.get(key);
        Object[] objects = JSON.parseObject(json, Object[].class);
        log.info("数组内的用户对象:{}" + objects[0]);
        log.info("数组内的TokenVo:{}" + objects[1]);
        TokenVO tokenVO = new TokenVO();
        //生成新的Token
        String newToken = UUIDUtils.getUUID32();
        log.info("新生成的Token:{}" + newToken);
        tokenVO.setToken(newToken);
        long time = new Date().getTime();
        tokenVO.setExpTime(userTokenTimeOut);
        tokenVO.setGenTime(time);
        //替换token，并且保存到redis中
        objects[1] = tokenVO;
        String key1 = RedisKeyUtils.formatKeyWithPrefix(Constants.Redis.PREFIX_TOKEN, newToken);
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            String s = objectMapper.writeValueAsString(objects);
            //token和用户信息保存到redis中
            redisUtil.setValue(key1, s, Constants.Redis_Expire.SESSION_TIMEOUT);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        //删除旧的token
        redisUtil.delete(key);
        return DtoUtil.returnDataSuccess(tokenVO);
    }


    //短信验证码登录接口
    @Override
    public Dto sendSms(String phone) {
        //判断邮箱还是手机号
        if (phone.contains("@")) {
            //是邮箱
            //验证邮箱格式
            Boolean flag = PatternUtil.isEmail(phone);
            if (!flag) {
                //不符合
                return DtoUtil.returnEnum(DtoEnum.COMMON_REG_EMAIL_PATTERN);
            }
            //格式符合
            //是否在冻结时间内
            //生成对应的前缀key
            //验证1分钟是否重复发送
            String key1 = RedisKeyUtils.formatKeyWithPrefix(Constants.Redis.REG_SMS, phone);
            String value = redisUtil.get(key1);
            if (!(value == null || value.equals(""))) {
                //5分钟之内发送过
                return DtoUtil.returnEnum(DtoEnum.COMMON_REG_TIME);
            }
            if (!this.checkEmail(phone).getErrorCode().equals(DtoUtil.returnSuccess().getErrorCode())) {
                return this.checkEmail(phone);
            }
            this.sendCode(phone);
            return DtoUtil.returnSuccess();

        }
        //是手机号 TODO

        return null;
    }

    private void sendCode(String phone) {

        //生成随机数
        Random random = new Random();
        Integer num = random.nextInt(9000) + 1000;
        //发送验证码，保存到redis中
        String key1 = RedisKeyUtils.formatKeyWithPrefix(Constants.Redis.REG_SMS, phone);//5
        String key = RedisKeyUtils.formatKeyWithPrefix(Constants.Redis.REG_SMS_ONE,phone); //10

        //保存到redis
        redisUtil.setValue(key, num.toString(), Constants.Redis_Expire.EMAIL_TIMEOUT);
        redisUtil.setValue(key1, num.toString(), Constants.Redis_Expire.EMAIL_EXPIRE);

        //发送邮件
        //发送消息到消息队列
        mqUtil.sendMessage(phone+","+num);
        //mailUtil.send(phone, "大咪网注册发送短信验证", "您好，您用于注册的短信验证码为：" + num);

    }

    @Override
    public Dto checkEmail(String phone) {
        //查询Phone有没有注册过了
        QueryWrapper<DmUser> queryWrapper = new QueryWrapper<>();//用于组装查询条件
        queryWrapper.eq("phone", phone);
        Integer count = dmUserMapper.selectCount(queryWrapper);
        if (count > 0) {
            //邮箱已经注册的情况
            return DtoUtil.returnEnum(DtoEnum.COMMON_REG_SMS_PHONE_ERROR);
        }
        //邮箱没有注册，返回成功
        return DtoUtil.returnSuccess();
    }

    //注册新用户
    @Override
    public Dto register(RegDto regDto) {

        //判断邮箱还是手机号
        if (regDto.getPhone().contains("@")) {
            //是邮箱
            //验证邮箱格式
            Boolean flag = PatternUtil.isEmail(regDto.getPhone());
            if (!flag) {
                //不符合
                return DtoUtil.returnEnum(DtoEnum.COMMON_REG_EMAIL_PATTERN);
            }
            //格式符合
            //邮箱有没有注册过
            if (!this.checkEmail(regDto.getPhone()).getErrorCode().equals(DtoUtil.returnSuccess().getErrorCode())) {
                return this.checkEmail(regDto.getPhone());
            }

            String key = RedisKeyUtils.formatKeyWithPrefix(Constants.Redis.REG_SMS_ONE,regDto.getPhone());
            String code = redisUtil.get(key);
            //redis中 不存在
            if(code == null || code.equals("")){
                return null;
            }
            log.info("从redis中获取的邮箱验证码:{}" + code);

            //判断验证码是否正确
            if (!regDto.getVcode().equals(code)) {//验证码错误的情况
                return DtoUtil.returnFail("验证码错误", "1004");
            }
            //删除redis中的验证码信息
            redisUtil.delete(key);
            //密码加密处理
            String password = MD5Utils.MD5(regDto.getPassword());
            log.info("加密后的密码:{}"+password);
            //验证码验证通过，入库
            DmUser dmUser = new DmUser();
            dmUser.setPhone(regDto.getPhone());
            dmUser.setPassword(password);
            dmUserMapper.insertUser(dmUser);
            return DtoUtil.returnSuccess();
        }
        //是手机 TODO
        return null;
    }

    //个人信息获取
    //根据token获取个人信息
    @Override
    public LoginUserVo queryUserInfoByToken(String token) {


        if (token == null || "".equals(token)) {
            return null;
        }
        String key = RedisKeyUtils.formatKeyWithPrefix(Constants.Redis.PREFIX_TOKEN,token);
        String json = redisUtil.get(key);

        if (json == null || json.equals("")) {
            return null;
        }
        JsonMapper jsonMapper = JsonMapper.builder().build();
        Object[] objects = null;
        try {
            objects = jsonMapper.readValue(json, Object[].class);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        LoginUserVo loginUser = null;


        if (objects != null && objects.length > 0) {
            Map<String, String> map = (HashMap) objects[0];
            try {
                String userJson = jsonMapper.writeValueAsString(map);
                loginUser = jsonMapper.readValue(userJson, LoginUserVo.class);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }


        return loginUser;
    }

    //用户信息修改---无头像修改
    @Override
    public Integer updateUser(String token, DmUser dmUser) {
        //修改用户信息
        QueryWrapper<DmUser> queryWrapper = new QueryWrapper<>();
        //从redis中获取用户信息
        LoginUserVo loginUserVo = this.queryUserInfoByToken(token);
        //将获取到的id传到里面
        dmUser.setId(loginUserVo.getUserId());
        queryWrapper.eq("id", loginUserVo.getUserId());
        int count = dmUserMapper.update(dmUser, queryWrapper);


        //根据token获取用户信息
        TokenVO tokenVO = new TokenVO();
        tokenVO.setToken(token);
        tokenVO.setExpTime(Constants.Redis_Expire.SESSION_TIMEOUT);
        tokenVO.setGenTime(System.currentTimeMillis());
        String key = RedisKeyUtils.formatKeyWithPrefix(Constants.Redis.PREFIX_TOKEN, token);

        LoginUserVo loginUserVo1 = new LoginUserVo();
        BeanUtils.copyProperties(dmUser, loginUserVo1);
        loginUserVo1.setUserId(loginUserVo.getUserId());
        loginUserVo1.setImgUrl(loginUserVo.getImgUrl());
        loginUserVo1.setImageId(loginUserVo.getImageId());
        Object[] objects = new Object[2];
        objects[0] = loginUserVo1;
        objects[1] = tokenVO;
        JsonMapper jsonMapper = JsonMapper.builder().build();
        String json = null;

        try {
            json = jsonMapper.writeValueAsString(objects);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        redisUtil.setValue(key, json, Constants.Redis_Expire.SESSION_TIMEOUT);
        return count;
    }

}
